;------------------------------------------------------------------------------
;Program:  scxtl.asm
;Author :  Wouter Caarls, Delft University of Technology
;Task   :  SmartCam XeTaL1 coprocessor program
;Works  :  By task scheduling a number of operations, which read from 
;       :  indirected line memories. Tasks can be added to the list and
;       :  completion can be signalled by I2C communications.
;------------------------------------------------------------------------------

; constants

$const maxword        31;

; coefficients

$const zero           0;
$const 1_2            1;
$const 1_4            2;
$const 1_8            3;
$const sca            4;
$const off            5;
$const linecountcoef  6;

; line memories

$const accu           -1; 

$const input          0;
$const output         1;

$const arg0          0;
$const arg1          1;
$const arg2          2;

$const sobely_preprev  6;
$const sobely_prev     7;
$const sobely_current  8;

$const sobelx_preprev  9;
$const sobelx_prev     10;
$const sobelx_current  11;

$const interpolate_prev 12;
$const interpolate_current 13;

$const captured       14;
$const processed      15;

$const ADC            16;
  
$const res_r          16;
$const res_g          17;
$const res_b          18;

; i2c communication registers

$const task_in_io     PREG0;
$const task_in_type   PREG1;
$const task_in_nr     PREG2;
$const task_out_fin   PREG3;

$const end_row        PREG4;
$const vert_blank     PREG12;

; control processor registers

$const task0_type     REG0;
$const task0_io       REG1;

$const task1_type     REG2;
$const task1_io       REG3;

$const task2_type     REG4;
$const task2_io       REG5;

$const task3_type     REG6;
$const task3_io       REG7;

$const task4_type     REG8;
$const task4_io       REG9;

$const task5_type     REG10;
$const task5_io       REG11;

$const task6_type     REG12;
$const task6_io       REG13;

$const task_nr        REG17;
$const task_type      REG18;
$const task_io        REG19;

$const temp           REG20;
$const temp2          REG21;
$const temp3          REG22;

$const num_blanking   REG23;
$const max_row        REG24;
$const linecount      REG25;

$const   contr_reg    REG27;

$begin

              SETCOEF  zero, 0;
              SETCOEF  1_2, 255;
              SETCOEF  1_4, 127;
              SETCOEF  1_8, 63;
              SETCOEF  sca, 511;
              SETCOEF  off, 511;

              LOADI    contr_reg,1;              start synchroniser
              ORI      contr_reg,8;              set start sensor interface
              ANDI     contr_reg,2039;           reset start sensor interface
              ORI      contr_reg,16;             start serial processor

; *** initialize ***

              LOADI    task_nr, maxword;
              OUTPAR   task_in_nr, task_nr;
              LOADI    task0_type, maxword;
              LOADI    task1_type, maxword;
              LOADI    task2_type, maxword;
              LOADI    task3_type, maxword;
              LOADI    task4_type, maxword;
              LOADI    task5_type, maxword;
              LOADI    task6_type, maxword;
              LOADI    max_row, 0;
              
; *** task scheduler ***

; communication
@SCHEDULE:    INPAR    task_nr, task_in_nr;      Check for communication
              COMPI    task_nr, maxword;
              JUMPE    CAPTURE;

              INPAR    task_type, task_in_type;  Get incoming task
              INPAR    task_io, task_in_io;
              COMPI    task_nr, 0;               switch(task)
              JUMPE    SET_TASK_0;
              COMPI    task_nr, 1;
              JUMPE    SET_TASK_1;
              COMPI    task_nr, 2;
              JUMPE    SET_TASK_2;
              COMPI    task_nr, 3;
              JUMPE    SET_TASK_3;
              COMPI    task_nr, 4;
              JUMPE    SET_TASK_4;
              COMPI    task_nr, 5;
              JUMPE    SET_TASK_5;
              COMPI    task_nr, 6;
              JUMPE    SET_TASK_6;
              COMPI    task_nr, 30;
              JUMPE    CLEAR_TASKS;
              JUMP     CLEARCOMM;

@SET_TASK_0:  LOAD     task0_type, task_type;    case 0:
              LOAD     task0_io, task_io;
              JUMP     CLEARCOMM;

@SET_TASK_1:  LOAD     task1_type, task_type;    case 1:
              LOAD     task1_io, task_io;
              JUMP     CLEARCOMM;

@SET_TASK_2:  LOAD     task2_type, task_type;    case 2:
              LOAD     task2_io, task_io;
              JUMP     CLEARCOMM;

@SET_TASK_3:  LOAD     task3_type, task_type;    case 3:
              LOAD     task3_io, task_io;
              JUMP     CLEARCOMM;

@SET_TASK_4:  LOAD     task4_type, task_type;    case 4:
              LOAD     task4_io, task_io;
              JUMP     CLEARCOMM;

@SET_TASK_5:  LOAD     task5_type, task_type;    case 5:
              LOAD     task5_io, task_io;
              JUMP     CLEARCOMM;

@SET_TASK_6:  LOAD     task6_type, task_type;    case 6:
              LOAD     task6_io, task_io;
              JUMP     CLEARCOMM;

@CLEAR_TASKS: LOADI    task0_type, maxword;
              LOADI    task1_type, maxword;
              LOADI    task2_type, maxword;
              LOADI    task3_type, maxword;
              LOADI    task4_type, maxword;
              LOADI    task5_type, maxword;
              LOADI    task6_type, maxword;
              JUMP     CLEARCOMM;

@CLEARCOMM:   LOADI    temp, maxword;
              OUTPAR   task_in_nr, temp;

; capturing
@CAPTURE:     COMPI    num_blanking, 0;          check for blanking
              JUMPG    DISPLAY;
              COMP     linecount, max_row;       check for capturing
              JUMPL    DOCAPTURE;
              
              INPAR    max_row, end_row;         start capturing              
              LOADI    linecount, 0;
              ORI      contr_reg, 4;             set active_region
@DOCAPTURE:   INC      linecount, 1;             capture a line
              WAITLINE;
              NOP;
              PASS     accu, ADC(0);
              ADD      captured(0), off;
              PASS     accu, ADC(1);
              ADD      captured(1), off;

; run tasks
@RUNTASKS:    LOADI    task_nr, 0;               check for task 0
              LOAD     task_type, task0_type;    
              LOAD     task_io, task0_io;
              CALL     RUNTASK;

              LOADI    task_nr, 1;               check for task 1
              LOAD     task_type, task1_type;    
              LOAD     task_io, task1_io;
              CALL     RUNTASK;  

              LOADI    task_nr, 2;               check for task 2
              LOAD     task_type, task2_type;    
              LOAD     task_io, task2_io;
              CALL     RUNTASK;  

              LOADI    task_nr, 3;               check for task 3
              LOAD     task_type, task3_type;    
              LOAD     task_io, task3_io;
              CALL     RUNTASK;  

              LOADI    task_nr, 4;               check for task 4
              LOAD     task_type, task4_type;    
              LOAD     task_io, task4_io;
              CALL     RUNTASK;  

              LOADI    task_nr, 5;               check for task 5
              LOAD     task_type, task5_type;    
              LOAD     task_io, task5_io;
              CALL     RUNTASK;  

              LOADI    task_nr, 6;               check for task 6
              LOAD     task_type, task6_type;    
              LOAD     task_io, task6_io;
              CALL     RUNTASK;  

              COMP     linecount, max_row;       check frame finished
              JUMPL    DISPLAY;
              LOADI    temp, 1;                  signal frame finished
              OUTPAR   task_out_fin, temp;

; display
@DISPLAY:     COMPI    num_blanking, 0;          check for blanking
              JUMPG    DOBLANKING;
              
@DODISPLAY:   PASS     res_r(0), processed(0);
              PASS     res_r(1), processed(1);
              ORI      contr_reg, 2;             set output line trigger
              ANDI     contr_reg, 2045;          reset output line trigger

              COMP     linecount, max_row;       check for vertical blanking
              JUMPL    SCHEDULE;

              INPAR    num_blanking, vert_blank; start blanking
              ANDI     contr_reg, 2043;          reset active_region
@DOBLANKING:  COMPI    num_blanking, 0;
              JUMPE    SCHEDULE;
              WAITLINE;
              NOP;
              DEC      num_blanking, 1;
              JUMP     SCHEDULE;

; subroutine to run one task
@RUNTASK:     LOADI    temp2, 0;                 get arg 0
              LOAD     temp, task_io;           
              LOAD     temp3, temp;
              ANDI     temp3, 7;        
              SETLMEMI temp2, temp3;
              LOADI    temp2, 1;                 get arg 1
              SHRL     temp;
              SHRL     temp;
              SHRL     temp;
              LOAD     temp3, temp;
              ANDI     temp3, 7;        
              SETLMEMI temp2, temp3;
              LOADI    temp2, 2;                 get arg 2
              SHRL     temp;
              SHRL     temp;
              SHRL     temp;
              LOAD     temp3, temp;
              ANDI     temp3, 7;        
              SETLMEMI temp2, temp3;
              
              COMPI    task_type, 24;
              JUMPE    READ;
              COMPI    task_type, 25;
              JUMPE    TRANSPORT;
              COMPI    task_type, 26;
              JUMPE    INTERPOLATE;
              COMPI    task_type, 27;
              JUMPE    BINARIZE;
              COMPI    task_type, 28;
              JUMPE    PLUS;
              COMPI    task_type, 29;
              JUMPE    SOBELX;
              COMPI    task_type, 30;
              JUMPE    SOBELY;
              COMPI    task_type, 31;
              JUMPE    AVG;
              
@ENDTASK:     RETN;         

; *** Read ***
@READ:        PASS     output(0), captured(0);
              PASS     output(1), captured(1);
              JUMP     ENDTASK;  

@INTERPOLATE: PASS     interpolate_prev(0), interpolate_current(0); Shift
              PASS     interpolate_prev(1), interpolate_current(1);
              PASS     interpolate_current(0), input(0);
              PASS     interpolate_current(1), input(1);

              MUL      accu, interpolate_prev(0), 1_4;
              MAC      accu, interpolate_prev(1), 1_4;
              MAC      accu, interpolate_current(0), 1_4;
              MAC      output(0), interpolate_current(1), 1_4;
              
              MUL      accu, interpolate_prev(1), 1_4;
              MAC      accu, interpolate_prev(2), 1_4;
              MAC      accu, interpolate_current(1), 1_4;
              MAC      output(1), interpolate_current(2), 1_4;
              JUMP     ENDTASK;

@SOBELX:      PASS     sobelx_preprev(0), sobelx_prev(0); Shift
              PASS     sobelx_preprev(1), sobelx_prev(1);
              PASS     sobelx_prev(0), sobelx_current(0); Shift
              PASS     sobelx_prev(1), sobelx_current(1);
              PASS     sobelx_current(0), input(0); Shift
              PASS     sobelx_current(1), input(1);
              
              PASS     accu, zero;
              SUB      accu, sobelx_preprev(-1);
              ADD      accu, sobelx_preprev(1);
              
              SUB      accu, sobelx_prev(-1);
              ADD      accu, sobelx_prev(1);
              SUB      accu, sobelx_prev(-1);
              ADD      accu, sobelx_prev(1);

              SUB      accu, sobelx_current(-1);
              ADD      accu, sobelx_current(1);
              
              ABSA     output(0);
              MULA     output(0), 1_2;
              
              PASS     accu, zero;
              SUB      accu, sobelx_preprev(0);
              ADD      accu, sobelx_preprev(2);
              
              SUB      accu, sobelx_prev(0);
              ADD      accu, sobelx_prev(2);
              SUB      accu, sobelx_prev(0);
              ADD      accu, sobelx_prev(2);

              SUB      accu, sobelx_current(0);
              ADD      accu, sobelx_current(2);
              
              ABSA     output(1);
              MULA     output(1), 1_2;
              
              JUMP     ENDTASK;
           
@SOBELY:      PASS     sobely_preprev(0), sobely_prev(0); Shift
              PASS     sobely_preprev(1), sobely_prev(1);
              PASS     sobely_prev(0), sobely_current(0); Shift
              PASS     sobely_prev(1), sobely_current(1);
              PASS     sobely_current(0), input(0); Shift
              PASS     sobely_current(1), input(1);
              
              PASS     accu, zero;
              SUB      accu, sobely_preprev(-1);
              ADD      accu, sobely_current(-1);
              
              SUB      accu, sobely_preprev(0);
              ADD      accu, sobely_current(0);
              SUB      accu, sobely_preprev(0);
              ADD      accu, sobely_current(0);

              SUB      accu, sobely_preprev(1);
              ADD      accu, sobely_current(1);

              ABSA     output(0);
              MULA     output(0), 1_2;
              
              PASS     accu, zero;
              SUB      accu, sobely_preprev(0);
              ADD      accu, sobely_current(0);
              
              SUB      accu, sobely_preprev(1);
              ADD      accu, sobely_current(1);
              SUB      accu, sobely_preprev(1);
              ADD      accu, sobely_current(1);

              SUB      accu, sobely_preprev(2);
              ADD      accu, sobely_current(2);

              ABSA     output(1);
              MULA     output(1), 1_2;

              JUMP     ENDTASK;

@PLUS:        PASS     accu, arg0(0);
              ADD      accu, arg1(0);
              MIN      arg2(0), 1_2;
              PASS     accu, arg0(1);
              ADD      accu, arg1(1);
              MIN      arg2(1), 1_2;
              JUMP     ENDTASK;

@AVG:         MUL      accu, arg0(0), 1_2;
              MAC      arg2(0), arg1(0), 1_2;
              MUL      accu, arg0(1), 1_2;
              MAC      arg2(1), arg1(1), 1_2;
              JUMP     ENDTASK;

@BINARIZE:    PASS     accu, arg0(0);
              MIN      accu, 1_8;
              PASS     arg1(0), zero;
              PASSC    arg1(0), 1_4;
              
              PASS     accu, arg0(0);
              MIN      accu, 1_4;
              PASS     accu, arg1(0);
              PASSC    arg1(0), 1_2;
              
              PASS     accu, arg0(1);
              MIN      accu, 1_8;
              PASS     arg1(1), zero;
              PASSC    arg1(1), 1_4;
              
              PASS     accu, arg0(1);
              MIN      accu, 1_4;
              PASS     accu, arg1(1);
              PASSC    arg1(1), 1_2;
              
              JUMP     ENDTASK;

; *** Transport ***
@TRANSPORT:   PASS     processed(0), input(0);
              PASS     processed(1), input(1);
              JUMP     ENDTASK;
              
@BLECH1:      WAITLINE;
              NOP;
              PASS     res_r(0), 1_2;
              PASS     res_r(1), 1_2;
              ORI      contr_reg, 2;             set output line trigger
              ANDI     contr_reg, 2045;          reset output line trigger
              JUMP BLECH1;

@BLECH2:      WAITLINE;
              NOP;
              PASS     res_r(0), 1_4;
              PASS     res_r(1), 1_4;
              ORI      contr_reg, 2;             set output line trigger
              ANDI     contr_reg, 2045;          reset output line trigger
              JUMP BLECH2;

$end
